1 module lib.gitdl; 2 3 import std.net.curl : download; 4 import std.stdio : writeln; 5 import std.format : format; 6 import std.file : tempDir, exists, remove, mkdirRecurse, write, readText; 7 import std.path : buildPath, dirName; 8 import std.stdio : stderr; 9 10 import lib.fs : moveRecurse, rmdirRecurseForce; 11 import lib.unzip : unzip; 12 13 private auto timesTried = 0; 14 15 /** 16 Download a Git repository from GitHub 17 18 Params: 19 user = The username 20 repo = The repository name 21 tag = The tag to download 22 dest = The destination path for the downloaded repository 23 stagingDir = The directory to download the zip file into and unzip it. By default a temp direcotry is used 24 retryTimes = The number of times to retrying downloading. Defaults to `5`. 25 */ 26 void gitdl(const string user, const string repo, const string tag, 27 const string dest, const string stagingDir = tempDir(), uint retryTimes = 5) 28 { 29 const cacheFile = buildPath(dest, ".gitdl_cache.txt"); 30 if (exists(dest) && exists(cacheFile)) 31 { 32 const cache = readText(cacheFile); 33 if (cache == tag) 34 { 35 writeln(format!"%s/%s#%s already downloaded to %s"(user, repo, tag, dest)); 36 return; 37 } 38 } 39 mkdirRecurse(stagingDir); // ensure that staging dir exits 40 const name = repo ~ "-" ~ (tag[0] == 'v' ? tag[1 .. $] : tag); // v is removed from the begining of the tag 41 const zipName = name ~ ".zip"; 42 const zipPath = buildPath(stagingDir, zipName); 43 const unzipDir = buildPath(stagingDir, name); 44 try 45 { 46 // downloading 47 writeln(format!"Downloading %s/%s#%s"(user, repo, tag)); 48 if (!(exists(zipPath))) // cache 49 { 50 download(format!"https://github.com/%s/%s/archive/refs/tags/%s.zip"(user, 51 repo, tag), zipPath); 52 } 53 // unzip 54 unzip(zipPath); 55 // copy to the destination 56 rmdirRecurseForce(dest); 57 mkdirRecurse(dest); 58 moveRecurse(unzipDir, dest); 59 } 60 catch (Exception e) 61 { 62 // start clean 63 remove(zipPath); 64 rmdirRecurseForce(unzipDir); 65 rmdirRecurseForce(dest); 66 if (timesTried > retryTimes) 67 { 68 throw e; 69 } 70 stderr.writeln("Download failed with: \n", e, "\n retrying..."); 71 timesTried++; 72 return gitdl(user, repo, tag, dest, stagingDir, retryTimes); 73 } 74 // when successful reset the times tried 75 timesTried = 0; 76 // write the cache 77 write(cacheFile, tag); 78 }